#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <stdarg.h>
#include <time.h>
#include <math.h>
#include <stdint.h>
#define SYMBOL_GLOBALS
#include "tools.h"
#undef SYMBOL_GLOBALS

//*----------------------------------------------------------------------------
//* 函数名称	: BCDToDecimal
//* 功能描述	: 将BCD编码转换为10进制（0x58->58）
//* 入口参数	: <bBCDCode>
//* 出口参数	: 十进制编码
//*----------------------------------------------------------------------------
uint8_t BCDToDecimal(uint8_t ubBCDCode)
{	
	return (uint8_t)(((ubBCDCode & 0xF0) >> 4) * 10 + (ubBCDCode & 0x0F));
}

void DecimalToBCD(uint32_t unDecimal, uint8_t *pubBCD, uint32_t unBCDBytes)
{
	int32_t i;  
	uint32_t unRemainVal;  
	for (i = unBCDBytes - 1; i >= 0; i--)  
	{  
		unRemainVal = unDecimal % 100;  
		pubBCD[i] = ((unRemainVal / 10) << 4) + ((unRemainVal % 10) & 0x0F);  
		unDecimal /= 100;  
		if(!unDecimal)
			break;
	}
}

uint8_t GetBCDFromDecimal(uint8_t ubDecimal)
{
  uint8_t ubRemainVal = ubDecimal % 100; 
  return ((ubRemainVal / 10) << 4) + ((ubRemainVal % 10) & 0x0F);  
}

//* 根据输入的日期就算当前是周几
/*
	基姆拉尔森计算公式
	W= (d+2*m+3*(m+1)/5+y+y/4-y/100+y/400) mod 7
	在公式中d表示日期中的日数，m表示月份数，y表示年数。
	注意：在公式中有个与其他公式不同的地方：
	把一月和二月看成是上一年的十三月和十四月，例：如果是2004-1-10则换算成：2003-13-10来代入公式计算。
 */
uint8_t CaculateWeekDay(uint32_t unYear, uint32_t unMonth, uint32_t unDay)
{
	uint32_t unWeek;
	
	if(unMonth == 1 || unMonth == 2) {
		unMonth += 12;
		unYear--;
	}
	
	unWeek = (unDay + 2 * unMonth + 3 * (unMonth + 1) / 5 + unYear + unYear / 4 - unYear / 100 + unYear / 400) % 7;
	return unWeek + 1;
}

//* ASCII的十进制数据转成BCD，如ASCII的字符串“20190421152542”->0x20190421152542
uint32_t ASCIIDecimalToBCDDecimal(const char *pszASCIIDecimal, uint32_t unASCIIDecimalLen, uint8_t *pubBCDDecimal, uint32_t unBCDDecimalLen)
{
	uint32_t i, j;
	
	if(unASCIIDecimalLen % 2)
		unASCIIDecimalLen -= 1;
	
	for(i=0, j=0; i<unASCIIDecimalLen && j<unBCDDecimalLen; i+=2, j++)
	{
		if(pszASCIIDecimal[i] > 0x29 && pszASCIIDecimal[i] < 0x40 && 
			 pszASCIIDecimal[i+1] > 0x29 && pszASCIIDecimal[i+1] < 0x40)
		{
			pubBCDDecimal[j] = ((pszASCIIDecimal[i] - 0x30) << 4) + pszASCIIDecimal[i+1] - 0x30;
		}
		else
			return j;
	}
	
	return j;
}

static const uint16_t l_usaCRC16[256] =
{
    0x0000,  0xC0C1,  0xC181,  0x0140,  0xC301,  0x03C0,  0x0280,  0xC241,
    0xC601,  0x06C0,  0x0780,  0xC741,  0x0500,  0xC5C1,  0xC481,  0x0440,
    0xCC01,  0x0CC0,  0x0D80,  0xCD41,  0x0F00,  0xCFC1,  0xCE81,  0x0E40,
    0x0A00,  0xCAC1,  0xCB81,  0x0B40,  0xC901,  0x09C0,  0x0880,  0xC841,
    0xD801,  0x18C0,  0x1980,  0xD941,  0x1B00,  0xDBC1,  0xDA81,  0x1A40,
    0x1E00,  0xDEC1,  0xDF81,  0x1F40,  0xDD01,  0x1DC0,  0x1C80,  0xDC41,
    0x1400,  0xD4C1,  0xD581,  0x1540,  0xD701,  0x17C0,  0x1680,  0xD641,
    0xD201,  0x12C0,  0x1380,  0xD341,  0x1100,  0xD1C1,  0xD081,  0x1040,
    0xF001,  0x30C0,  0x3180,  0xF141,  0x3300,  0xF3C1,  0xF281,  0x3240,
    0x3600,  0xF6C1,  0xF781,  0x3740,  0xF501,  0x35C0,  0x3480,  0xF441,
    0x3C00,  0xFCC1,  0xFD81,  0x3D40,  0xFF01,  0x3FC0,  0x3E80,  0xFE41,
    0xFA01,  0x3AC0,  0x3B80,  0xFB41,  0x3900,  0xF9C1,  0xF881,  0x3840,
    0x2800,  0xE8C1,  0xE981,  0x2940,  0xEB01,  0x2BC0,  0x2A80,  0xEA41,
    0xEE01,  0x2EC0,  0x2F80,  0xEF41,  0x2D00,  0xEDC1,  0xEC81,  0x2C40,
    0xE401,  0x24C0,  0x2580,  0xE541,  0x2700,  0xE7C1,  0xE681,  0x2640,
    0x2200,  0xE2C1,  0xE381,  0x2340,  0xE101,  0x21C0,  0x2080,  0xE041,
    0xA001,  0x60C0,  0x6180,  0xA141,  0x6300,  0xA3C1,  0xA281,  0x6240,
    0x6600,  0xA6C1,  0xA781,  0x6740,  0xA501,  0x65C0,  0x6480,  0xA441,
    0x6C00,  0xACC1,  0xAD81,  0x6D40,  0xAF01,  0x6FC0,  0x6E80,  0xAE41,
    0xAA01,  0x6AC0,  0x6B80,  0xAB41,  0x6900,  0xA9C1,  0xA881,  0x6840,
    0x7800,  0xB8C1,  0xB981,  0x7940,  0xBB01,  0x7BC0,  0x7A80,  0xBA41,
    0xBE01,  0x7EC0,  0x7F80,  0xBF41,  0x7D00,  0xBDC1,  0xBC81,  0x7C40,
    0xB401,  0x74C0,  0x7580,  0xB541,  0x7700,  0xB7C1,  0xB681,  0x7640,
    0x7200,  0xB2C1,  0xB381,  0x7340,  0xB101,  0x71C0,  0x7080,  0xB041,
    0x5000,  0x90C1,  0x9181,  0x5140,  0x9301,  0x53C0,  0x5280,  0x9241,
    0x9601,  0x56C0,  0x5780,  0x9741,  0x5500,  0x95C1,  0x9481,  0x5440,
    0x9C01,  0x5CC0,  0x5D80,  0x9D41,  0x5F00,  0x9FC1,  0x9E81,  0x5E40,
    0x5A00,  0x9AC1,  0x9B81,  0x5B40,  0x9901,  0x59C0,  0x5880,  0x9841,
    0x8801,  0x48C0,  0x4980,  0x8941,  0x4B00,  0x8BC1,  0x8A81,  0x4A40,
    0x4E00,  0x8EC1,  0x8F81,  0x4F40,  0x8D01,  0x4DC0,  0x4C80,  0x8C41,
    0x4400,  0x84C1,  0x8581,  0x4540,  0x8701,  0x47C0,  0x4680,  0x8641,
    0x8201,  0x42C0,  0x4380,  0x8341,  0x4100,  0x81C1,  0x8081,  0x4040,
};
uint16_t crc16(const uint8_t *pubCheckData, uint32_t unCheckLen, uint16_t usInitVal)
{
    uint32_t i;
    uint16_t usCRC = usInitVal;
    for (i = 0; i < unCheckLen; i++)
    {
        usCRC = (usCRC >> 8) ^ l_usaCRC16[(usCRC & 0x00FF) ^ *pubCheckData];
        pubCheckData++;
    }

    return usCRC;
}

void GetSystemWeekEngShort(uint8_t ubWeekDay, char *pszSystemWeek)
{
  switch (ubWeekDay)
	{
	case 7:
		sprintf(pszSystemWeek, "Sun.");
		break;

	case 1:
		sprintf(pszSystemWeek, "Mon.");
		break;

	case 2:
		sprintf(pszSystemWeek, "Tues.");
		break;

	case 3:
		sprintf(pszSystemWeek, "Wed.");
		break;

	case 4:
		sprintf(pszSystemWeek, "Thur.");
		break;

	case 5:
		sprintf(pszSystemWeek, "Fri.");
		break;

	case 6:
		sprintf(pszSystemWeek, "Sat.");
		break;
	}
}
